﻿using System;
using System.Collections.Generic;
using System.Linq;

using BEX.DataAccess;
using BEX.Core;
using BEX.Core.Exchange;

namespace BEX.RuleMonitor
{
    public class ArbitrageRule : AlertRule
    {

        private ExchangeType _exchangeB;

        public ExchangeType ExchangeA
        {
            get
            {

                return this.SourceExchange;
            }
            set
            {
                this.SourceExchange = value;
            }
        }

        public ExchangeType ExchangeB
        {
            get
            {
                return _exchangeB;
            }
            set
            {
                _exchangeB = value;
            }
        }

        public decimal Percent { get; set; }

        public ArbitrageRule()
        {
        }

        public ArbitrageRule(int ID)
        {
            LoadRule(ID);
        }

        public ArbitrageRule(ExchangeType exchangeA, ExchangeType exchangeB, CurrencyPair pair, decimal percent)
        {
            Percent = percent;
            _pair = pair;
            SourceExchange = exchangeA;
            ExchangeB = exchangeB;

            LoadRule(exchangeA, exchangeB, pair, percent);
        }

        private bool LoadRule(ExchangeType exchangeA, ExchangeType exchangeB, CurrencyPair pair, decimal percent)
        {
            var res = false;

            var _context = new BTCDataClassesDataContext();

            var _a = (from acc in _context.GetTable<ALERT_RULE_ARBITRAGE>()
                      where (acc.EXCHANGE_A == (int)exchangeA
                                                       && acc.EXCHANGE_B == (int)(exchangeB)
                                                       && acc.BASE_CURRENCY_ID == (int)(pair.Base)
                                                       && acc.COUNTER_CURRENCY_ID == (int)(pair.Counter)
                                                       && acc.PERCENTAGE == percent
                      )
                      select acc).ToList<ALERT_RULE_ARBITRAGE>();

            if (null != _a && _a.Count > 0)
            {
                this._id = _a[0].ID;
                this.Percent = _a[0].PERCENTAGE;
                this._pair = new CurrencyPair() { Base = (CurrencyType)_a[0].BASE_CURRENCY_ID, Counter = (CurrencyType)_a[0].COUNTER_CURRENCY_ID };
                this.SourceExchange = (ExchangeType)((int)_a[0].EXCHANGE_A);
                
                this.ExchangeB = (ExchangeType)((int)_a[0].EXCHANGE_B);


                res = true;
            }

            return res;
        }

        private bool LoadRule(int ID)
        {
            var res = false;

            var _context = new BTCDataClassesDataContext();

            var _a = (from acc in _context.GetTable<ALERT_RULE_ARBITRAGE>()
                      where (acc.ID == ID)
                      select acc).ToList<ALERT_RULE_ARBITRAGE>();

            if (null != _a && _a.Count > 0)
            {
                this._id = _a[0].ID;
                this.Percent = _a[0].PERCENTAGE;
                this._pair = new CurrencyPair() { Base = (CurrencyType)_a[0].BASE_CURRENCY_ID, Counter = (CurrencyType)_a[0].COUNTER_CURRENCY_ID };
               
                this.SourceExchange = (ExchangeType)((int)_a[0].EXCHANGE_A);
                this.ExchangeB = (ExchangeType)((int)_a[0].EXCHANGE_B);

                res = true;
            }

            return res;
        }

        public override void AddAccount(int AccID)
        {
            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ACCOUNT_RULE_ARBITRAGE>()
                         where (c.RULE_ID == this.ID && c.ACCOUNT_ID == AccID)
                         select c).SingleOrDefault();

            if (null == _rule)
            {
                var _acc = GetAccountRuleTable();

                var _a = new ACCOUNT_RULE_ARBITRAGE();

                _a.ACCOUNT_ID = AccID;
                _a.RULE_ID = this.ID;

                _acc.InsertOnSubmit(_a);
                _acc.Context.SubmitChanges();
            }
        }

        public override void RemoveAccount(int AccID)
        {
            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ACCOUNT_RULE_ARBITRAGE>()
                         where (c.RULE_ID == this.ID && c.ACCOUNT_ID == AccID)
                         select c).Single();

            if (null != _rule)
            {
                _context.ACCOUNT_RULE_ARBITRAGEs.DeleteOnSubmit(_rule);
                _context.SubmitChanges();
            }
        }

        public override List<int> GetAccountIDList()
        {
            var res = new List<int>();

            var _context = new BTCDataClassesDataContext();

            var _l = (from acc in _context.GetTable<ACCOUNT_RULE_ARBITRAGE>()
                      where (acc.RULE_ID == _id)
                      select acc).ToList<ACCOUNT_RULE_ARBITRAGE>();

            foreach (ACCOUNT_RULE_ARBITRAGE _r in _l)
            {
                res.Add(_r.ACCOUNT_ID);
            }

            return res;
        }

        public override bool Test(Tick current)
        {
            var _src = current.ExchangeSource;
            ExchangeType _counter;
            
            if (SourceExchange == _src)
            {
                _counter = ExchangeB;
            }
            else
            {
                _counter = SourceExchange;
            }
            var _counterTick = TickDAL.GetCurrentTick(_counter, current.Currency);

            if (current != null && _counterTick != null)
            {
                var _p = (Convert.ToDecimal(Math.Abs(current.Spot) - Math.Abs(_counterTick.Spot)) / Convert.ToDecimal(Math.Abs(_counterTick.Spot))) * 100;
                var _p2 = (Convert.ToDecimal(Math.Abs(_counterTick.Spot) - Math.Abs(current.Spot)) / Convert.ToDecimal(Math.Abs(current.Spot))) * 100;

                if ((_p >= Percent) || (_p2 >= Percent))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            return false;
        }

        public static List<ArbitrageRule> GetListForAccount(int AcctID)
        {
            var _l = AlertRuleList();

            var _ids = GetRuleIDs(AcctID);

            var res = new List<ArbitrageRule>();

            foreach (ALERT_RULE_ARBITRAGE _a in _l)
            {
                if (_ids.Contains(_a.ID))
                {
                    res.Add(new ArbitrageRule(_a.ID));
                }
            }

            return res;
        }

        private static List<int> GetRuleIDs(int AcctID)
        {
            var res = new List<int>();

            var _context = new BTCDataClassesDataContext();

            var _l = (from acc in _context.GetTable<ACCOUNT_RULE_ARBITRAGE>()
                      where (acc.ACCOUNT_ID == AcctID)
                      select acc).ToList<ACCOUNT_RULE_ARBITRAGE>();

            foreach (ACCOUNT_RULE_ARBITRAGE _r in _l)
            {
                res.Add(_r.RULE_ID);
            }

            return res;
        }

        private static List<ALERT_RULE_ARBITRAGE> AlertRuleList()
        {
            var _context = new BTCDataClassesDataContext();

            return (from acc in _context.GetTable<ALERT_RULE_ARBITRAGE>()
                    select acc).ToList<ALERT_RULE_ARBITRAGE>();
        }

        public bool Save()
        {
            var res = true;

            var _context = new BTCDataClassesDataContext();

            var _rule = (from c in _context.GetTable<ALERT_RULE_ARBITRAGE>()
                         where c.ID == this.ID
                         select c).SingleOrDefault();

            if (null == _rule)
            {
                var _acc = GetAlertRuleTable();
                var _a = new ALERT_RULE_ARBITRAGE();

                _a.EXCHANGE_A = (int?)SourceExchange;
                _a.EXCHANGE_B = (int)(ExchangeB);
                _a.PERCENTAGE = Percent;
                _a.COUNTER_CURRENCY_ID = (int)_pair.Counter;
                _a.BASE_CURRENCY_ID = (int)_pair.Base;

                _acc.InsertOnSubmit(_a);
                _acc.Context.SubmitChanges();

                this.ID = _a.ID;
            }
            else
            {
                _rule.EXCHANGE_A = (int?)(SourceExchange);
                _rule.EXCHANGE_B = (int)(ExchangeB);
                _rule.COUNTER_CURRENCY_ID = (int)_pair.Counter;
                _rule.BASE_CURRENCY_ID = (int)_pair.Base;
                _rule.PERCENTAGE = Percent;

                _context.SubmitChanges();
            }

            return res;
        }

        private static System.Data.Linq.Table<ACCOUNT_RULE_ARBITRAGE> GetAccountRuleTable()
        {
            var _context = new BTCDataClassesDataContext();

            return _context.GetTable<ACCOUNT_RULE_ARBITRAGE>();
        }

        private static System.Data.Linq.Table<ALERT_RULE_ARBITRAGE> GetAlertRuleTable()
        {
            var _context = new BTCDataClassesDataContext();

            return _context.GetTable<ALERT_RULE_ARBITRAGE>();
        }

        public static List<ArbitrageRule> GetArbitrageRuleList()
        {
            var _l = AlertRuleList();

            var res = new List<ArbitrageRule>();

            foreach (ALERT_RULE_ARBITRAGE _a in _l)
            {
                res.Add(new ArbitrageRule(_a.ID));
            }

            return res;
        }
    }
}
